package com.candy.candycommon.exception;

import com.alibaba.fastjson2.JSONObject;
import com.candy.candycommon.Event.ExceptionEvent;
import com.candy.candycommon.utils.ApplicationContentUtils;
import com.candy.candycommon.utils.ResultBean;
import com.gitee.candy.string.StringUtils;
import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.ConnectException;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 * @author suYanLong
 * @date 2022年09月29日 17:36
 * TODO 使用seata分布式事务后全局事务回滚，返回异常信息
 *  如果httpStatus状态是200，seata事务不会回滚
 *  全局异常拦截处理后，需要将httpStatus状态设置为非200，seata全局事务才会进行回滚操作
 *  但是这个时候返回给接口调用者的请求状态就不是200了。
 *   两种方案解决：
 *   1、与接口调用放协商好
 *   2、网关层总入口去处理
 *   ----------------------------
 *   解决方案参考：
 *   https://mp.weixin.qq.com/s/4EWOEZVnLb-7FxHAUZzgZA
 */
@Slf4j
@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler(ConnectException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResultBean connectException(ConnectException e) {
        this.currencyLogic(e);
        return ResultBean.error(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public ResultBean sqlIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
        this.currencyLogic(e);
        return ResultBean.error(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(DuplicateKeyException.class)
    public ResultBean duplicateKeyException(DuplicateKeyException e) {
        this.currencyLogic(e);
        return ResultBean.error(ResultBean.ExceptionEnums.duplicateKeyException.getMsg());
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResultBean businessException(BusinessException e) {
        this.currencyLogic(e);
        this.handlerSeataTransactionRollback();
        return ResultBean.error(e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResultBean baseException(Exception e) {
        this.currencyLogic(e);
        String message = e.getMessage();
        if (StringUtils.isNotBlank(message)) {
            String[] split = message.split("]: \\[");
            String s = split[1];
            String substring = s.substring(0, s.length() - 1);
            return JSONObject.parseObject(substring, ResultBean.class);
        }
        this.handlerSeataTransactionRollback();
        return ResultBean.error(e.getMessage());
    }

    private void handlerSeataTransactionRollback() {
        if (StringUtils.isNotEmpty(RootContext.getXID())) {
            log.info("分布式全局事务XID:{}", RootContext.getXID());
//            try {
//                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
//            } catch (TransactionException ex) {
//                throw new RuntimeException(ex);
//            }
        }
    }

    private void currencyLogic(Exception e) {
        log.error(e.getMessage());
        ApplicationContentUtils.getApplicationContext().publishEvent(new ExceptionEvent.SendExceptionEvent("currencyLogic", e));
    }

}
